<?php

class DBConnection
{
    static private $LIKE_EXPRESSION_SPECIAL_CHARS = array('%', '_');

    /**
     *
     * @var mysqli
     */
    private $dbLink = null;

    public function __construct( $dbLink = null )
    {
        $this->dbLink = $dbLink;
    }

    public function Connect( $host, $username, $password, $port, $socket, $new_link = null )
    {
        $this->Close();

        $this->dbLink = new mysqli( $host, $username, $password, $new_link, $port, $socket );
        if ( $this->dbLink->connect_errno )
        {
            throw new Exception( "Could not connect to DB:\n". $this->dbLink->connect_error );
        }
    }

    public function SelectDB( $dbName )
    {
        $this->dbLink->select_db( $dbName );
        if ( $this->dbLink->errno )
        {
            throw new Exception( "Could not select database '$dbName':\n". $this->GetErrorMessage() );
        }
    }

    public function Close()
    {
        if ( !is_null($this->dbLink) )
        {
            $closed = $this->dbLink->close();
            $this->dbLink = null;
            if ( !$closed )
            {
                throw new Exception( 'Could not close: '. $this->GetErrorMessage() );
            }
        }
    }

    private function GetErrorMessage()
    {
        return $this->dbLink->error;
    }

    private function PrepareArray( &$values )
    {
        foreach ( $values as &$value )
        {
            if ( is_bool($value) )
            {
                $value = $value ? "'1'" : "'0'";
            }
            else if ( is_null($value) )
            {
                $value = "NULL";
            }
            else if ( !is_numeric($value) )
            {
                $value = "'$value'";
            }
        }
    }

    /**
     * Execute query to db.
     *
     * @param string $query
     * @param array $substs
     * @return DBQueryResult
     */
    public function Query( $query, $substs = array() )
    {
        if ( is_array($substs) )
        {
            $this->PrepareArray( $substs );
            $query = strtr($query, $substs);
        }
        else
        {
            $params = func_get_args();
            array_shift( $params );
            if ( !empty($params) )
            {
                $this->PrepareArray( $params );
                array_unshift( $params, $query );
                $query = call_user_func_array( "sprintf", $params );
            }
        }

        $query = preg_replace( "/^\s+/m", "", $query );
        $query = str_replace( array("\r\n","\n"), " ", $query );

        $result = $this->dbLink->query( $query );
        if ( !$result )
        {
            Logger::Log(APP_LOG_FILE, "Could not execute query: " . $query);
            throw new Exception( "Could not execute query '".substr($query, 0, 100)."':\n". $this->GetErrorMessage() );
        }
        return new DBQueryResult( $result );
    }

    public function GetLastInsertId()
    {
        return $this->dbLink->insert_id;
    }

    public function GetAffectedRowsCount()
    {
        return $this->dbLink->affected_rows;
    }

    public function Quote( $value )
    {
        if ( is_string($value) )
        {
            return $this->dbLink->real_escape_string( $value );
        }
        return $value;
    }

    /**
    * Escapes special chars used in the "LIKE" expressions
    *
    * @param string $value
    * @return string
    */
    public function QuoteForLikeExpression( $value )
    {
        $value = str_replace('\\', '\\\\', $value);
        $search = array();
        $replace = array();
        foreach ( self::$LIKE_EXPRESSION_SPECIAL_CHARS as $searchChar )
        {
            $replaceChar = '\\' . $searchChar;
            $replace[] = $replaceChar;
            $search[]  = $searchChar;
        }
        return str_replace( $search, $replace, $value );
    }

    /**
     * Return total rows count
     *
     * @return int
     */
    public static function GetTotalRowsCount()
    {
        $sql = 'SELECT FOUND_ROWS() as total';
        $data = Core::DBConn()->Query($sql)->GetAssoc();
        return intval( $data["total"] );
    }
}

?>
